package com.by.basicweb.advice;

import com.by.toolkit.exceptions.ServiceException;
import com.by.toolkit.model.Resp;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import static com.by.toolkit.utils.ExceptionUtil.getStackTrace;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionAdvice {

    @ExceptionHandler(ServiceException.class)
    public Resp<String> serviceExceptionHandler(ServiceException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionAdvice][serviceExceptionHandler] uri:[{}] hasException:[{}]", request.getRequestURI(), ExceptionUtils.getStackTrace(e));
        return Resp.fail(e.getCode(), e.getMsg(), e.getData());
    }

    @SuppressWarnings("unchecked")
    @ExceptionHandler(Exception.class)
    public Resp<Void> exceptionHandler(Exception e, HttpServletRequest request) {
        log.error("[GlobalExceptionAdvice][exceptionHandler] uri:[{}] hasException:[{}] ", request.getRequestURI(), ExceptionUtils.getStackTrace(e));
        return Resp.sysError();
    }

    /**
     * GET/POST请求方法错误的拦截器
     * 因为开发时可能比较常见,而且发生在进入controller之前,上面的拦截器拦截不到这个错误
     * 所以定义了这个拦截器
     */
    @SuppressWarnings("unchecked")
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Resp<Void> httpRequestMethodHandler(HttpRequestMethodNotSupportedException e, HttpServletRequest request) {
        return Resp.httpMethodUnsupport();
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Resp<Void> methodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        log.warn("[GlobalExceptionAdvice][methodArgumentNotValidException] uri:[{}] msg:[{}] hasException:[{}] ", request.getRequestURI(), fieldError.getDefaultMessage(), ExceptionUtils.getStackTrace(e));
        return Resp.bizFail(fieldError.getDefaultMessage());
    }

    @ExceptionHandler(BindException.class)
    public Resp<Void> handleBindException(BindException e, HttpServletRequest request) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        log.warn("[GlobalExceptionAdvice][handleBindException] uri:[{}] msg:[{}] hasException:[{}] ", request.getRequestURI(), fieldError.getDefaultMessage(), ExceptionUtils.getStackTrace(e));
        return Resp.bizFail(fieldError.getDefaultMessage());
    }

    @ExceptionHandler(ServletRequestBindingException.class)
    public Resp<Void> ServletRequestBindingException(ServletRequestBindingException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionAdvice][ServletRequestBindingException] uri:[{}] hasException:[{}] ", request.getRequestURI(), ExceptionUtils.getStackTrace(e));
        return Resp.bizFail(e.getMessage());
    }

    /**
     * 参数类型不匹配，比如字段是整型前台传的是字符串。
     * 在用户输入的地方，前台没有校验会出现这个异常
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Resp<Void> httpMessageNotReadableException(HttpMessageNotReadableException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionAdvice][httpMessageNotReadableException] uri:[{}] hasException:[{}] ", request.getRequestURI(), ExceptionUtils.getStackTrace(e));
        return Resp.paramChkError();
    }

    @ExceptionHandler(RpcException.class)
    public Resp<Void> rpcExceptionHandler(RpcException e, HttpServletRequest request) {
        log.error("[GlobalExceptionAdvice][rpcExceptionHandler] uri:[{}] hasException:[{}] ", request.getRequestURI(), getStackTrace(e));
        return Resp.sysError();
    }

}
